package com.icw.decoupling.defi.tool;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.StringUtils;

import com.icw.decoupling.defi.proxy.GenericSrvProxy;
import com.icw.resource.inner.entity.IcwDict;
import com.icw.resource.inner.entity.IcwDictGroup;
import com.icw.utility.BeanCtxUtils;
import com.icw.utility.IcwUtils;
import com.icw.utility.InitializeUtil;
import com.icw.utility.query.IcwCriteria;

import lombok.Getter;
import lombok.Setter;

public interface DictManager {

	Set<String> dictGroupNames() throws Exception;

	Map<String, String> dictGroup(String dictGroupName) throws Exception;

	String dict(String dictGroupName, String code) throws Exception;

	void add(String dictGroupName, String code, String value) throws Exception;

	static void entityTypeInit() throws Exception {
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		Set<Class<?>> classes = IcwUtils.getAllEntities();
		List<IcwDictGroup> list = srv.query(IcwDictGroup.class, new IcwCriteria("eq", "name", "ENTITY_TYPE"), null);
		IcwDictGroup entityTypeGroup;
		if (list.size() == 1) {
			entityTypeGroup = list.get(0);
		} else if (list.size() == 0) {
			entityTypeGroup = null;
		} else {
			throw new Exception("Duplicate Group Name ENTITY_TYPE");
		}
		Set<String> forInserts;
		Integer maxSno;
		Set<String> currentCodeSet = classes.stream().map(c -> c.getSimpleName()).collect(Collectors.toSet());
		if (entityTypeGroup == null) {
			forInserts = currentCodeSet;
			entityTypeGroup = new IcwDictGroup();
			entityTypeGroup.setName("ENTITY_TYPE");
			srv.save(entityTypeGroup);
			maxSno = 0;
		} else {
			List<IcwDict> existDictTypeList = srv.query(IcwDict.class, new IcwCriteria("eq", "dictGroup.name", "ENTITY_TYPE"), null);
			Set<String> existCodeSet = existDictTypeList.stream().map(d -> d.getCode()).collect(Collectors.toSet());
			if (!SetUtils.isEqualSet(existCodeSet, currentCodeSet)) {
				forInserts = SetUtils.difference(currentCodeSet, existCodeSet);
				Set<String> forDeletes = SetUtils.difference(existCodeSet, currentCodeSet);
				Set<String> forIntercs = SetUtils.intersection(existCodeSet, currentCodeSet);
				String maxSnoStr = forIntercs.size() == 0 ? "00" : existDictTypeList.stream().filter(d -> forIntercs.contains(d.getCode())).max((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(a.getCode(), b.getCode())).get().getSno();
				maxSno = Integer.parseInt(maxSnoStr, 10);
				srv.deleteByCriteria(IcwDict.class, new IcwCriteria("eq", "dictGroup.name", "ENTITY_TYPE", "in", "code", forDeletes));
			} else {
				forInserts = SetUtils.emptySet();
				maxSno = null;
			}
		}
		for (String temp : forInserts) {
			IcwDict dict = new IcwDict();
			dict.setValue(temp);
			dict.setCode(temp);
			dict.setSno(StringUtils.leftPad((++maxSno) + "", 3, "0"));
			dict.setDictGroup(entityTypeGroup);
			srv.save(dict);
		}
	}

	static void defaultInit() throws Exception {
		new Init03xIcwDict().execInitlize();
	}

	static void initDictCache() throws Exception {
		DictManager dm = BeanCtxUtils.getBeanByType(DictManager.class);
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		List<IcwDict> dictList = srv.query(IcwDict.class, new IcwCriteria(), null);
		for (IcwDict temp : dictList) {
			dm.add(temp.getDictGroup().getName(), temp.getCode(), temp.getValue());
		}
	}

	static class Init03xIcwDict {

		private void execInitlize() throws Exception {
			GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
			if (srv.countByCriteria(IcwDict.class, null) == 0) {
				postDicts();
			}
		}

		@Getter
		@Setter
		private IcwDictGroup dictGroup;

		@Getter
		@Setter
		private int sno = 0;

		private void postDicts() throws Exception {
			InitializeUtil.forEachLine("icw/Init03xIcwDict.resource", dataStr -> {
				if (dataStr.indexOf(",") == -1) {
					// 1. INIT SNO
					setSno(1);
					// 2. INIT GROUP
					setDictGroup(new IcwDictGroup());
					getDictGroup().setName(dataStr.trim());
					// 3. SAVE GROUP
					InitializeUtil.forceSave(getDictGroup());
				} else {
					int splitIndex = dataStr.indexOf(",");
					String code = dataStr.substring(0, splitIndex);
					String value = dataStr.substring(splitIndex + 1, dataStr.length());
					IcwDict dict = new IcwDict();
					dict.setCode(code);
					dict.setValue(value);
					dict.setDictGroup(getDictGroup());
					dict.setSno(StringUtils.leftPad(getSno() + "", 3, '0'));
					InitializeUtil.forceSave(dict);
					setSno(getSno() + 1);
				}
			});
		}
	}
}
